package au.edu.qut.bpm.genbinder.ui;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
import java.util.Set;

import org.jzy3d.chart.Chart;
import org.jzy3d.chart.ChartLauncher;
import org.jzy3d.colors.Color;
import org.jzy3d.colors.ColorMapper;
import org.jzy3d.colors.colormaps.ColorMapRainbow;
import org.jzy3d.maths.Coord3d;
import org.jzy3d.maths.Pair;
import org.jzy3d.plot3d.builder.Tessellator;
import org.jzy3d.plot3d.builder.concrete.OrthonormalTessellator;
import org.jzy3d.plot3d.builder.delaunay.DelaunayTessellator;
import org.jzy3d.plot3d.primitives.AbstractComposite;

import au.edu.qut.bpm.genbinder.genetic.evaluation.LogEvaluator;
import au.edu.qut.bpm.genbinder.models.Activity;
import au.edu.qut.bpm.genbinder.models.ConcreteEventLog;
import au.edu.qut.bpm.genbinder.models.Resource;

public class CostLandscapeVisualizer {
	// This is mostly experimental / ideas for now
	// Maybe implement some kind of distance function?

	public CostLandscapeVisualizer(List<ConcreteEventLog> population,
			Activity activityOfInterest,
			LogEvaluator evaluator) {
		List<Coord3d> coordinates = new ArrayList<Coord3d>();

		List<Set<Resource>> resourceAllocationIndexes = new ArrayList<Set<Resource>>();
		Map<Pair<Long, Long>, Double> coords = new HashMap<Pair<Long, Long>, Double>();

		for (ConcreteEventLog log : population) {
			double cost = evaluator.getCost(log);
			long time = log.getActivityStart(activityOfInterest);
			Set<Resource> resAllocs = log.getActivityResources(activityOfInterest);
			int ir = resourceAllocationIndexes.indexOf(resAllocs);
			if (ir == -1) {
				resourceAllocationIndexes.add(resAllocs);
				ir = resourceAllocationIndexes.size() - 1;
			}
			Pair<Long, Long> pair = new Pair<Long, Long>((long) ir, time);
			if (!coords.containsKey(pair)
					|| coords.get(pair) > cost)
				coords.put(pair, cost);
		}
		for (Entry<Pair<Long, Long>, Double> e : coords.entrySet()) {
			coordinates.add(new Coord3d(e.getKey().a, e.getKey().b, e.getValue()));
		}

		Tessellator tesselator = new OrthonormalTessellator();
		AbstractComposite composite = tesselator.build(coordinates);

		composite.setColorMapper(new ColorMapper(new ColorMapRainbow(),
				composite.getBounds().getZmin(), composite.getBounds()
						.getZmax(), new org.jzy3d.colors.Color(1, 1, 1, 1f)));
		composite.setWireframeDisplayed(false);
		composite.setWireframeColor(org.jzy3d.colors.Color.BLACK);

		Chart chart = new Chart();
		chart.getAxeLayout().setMainColor(Color.BLACK);
		chart.getView().setBackgroundColor(Color.WHITE);
		chart.getScene().add(composite);
		ChartLauncher.openChart(chart);
	}

	public CostLandscapeVisualizer(List<ConcreteEventLog> population,
			Set<Activity> activitiesOfInterest,
			LogEvaluator evaluator) {
		List<Coord3d> coordinates = new ArrayList<Coord3d>();

		// Stupid way to determine axes for now
		List<List<Long>> timeAllocationIndexes = new ArrayList<List<Long>>();
		List<List<Set<Resource>>> resourceAllocationIndexes = new ArrayList<List<Set<Resource>>>();

		for (ConcreteEventLog log : population) {
			double cost = evaluator.getCost(log);
			List<Long> timeAllocs = new ArrayList<Long>();
			List<Set<Resource>> resAllocs = new ArrayList<Set<Resource>>();
			for (Activity a : activitiesOfInterest) {
				timeAllocs.add(log.getActivityStart(a));
				resAllocs.add(log.getActivityResources(a));
			}
			int it = timeAllocationIndexes.indexOf(timeAllocs);
			int ir = resourceAllocationIndexes.indexOf(resAllocs);
			if (it == -1) {
				timeAllocationIndexes.add(timeAllocs);
				it = timeAllocationIndexes.size() - 1;
			}
			if (ir == -1) {
				resourceAllocationIndexes.add(resAllocs);
				ir = resourceAllocationIndexes.size() - 1;
			}
			coordinates.add(new Coord3d(ir, it, cost));
			System.err.println(ir + " , " + it + " -> " + cost);
		}

		// TODO: Add smoothing?

		Tessellator tesselator = new DelaunayTessellator();
		AbstractComposite composite = tesselator.build(coordinates);

		composite.setColorMapper(new ColorMapper(new ColorMapRainbow(),
				composite.getBounds().getZmin(), composite.getBounds()
						.getZmax(), new org.jzy3d.colors.Color(1, 1, 1, 1f)));
		composite.setWireframeDisplayed(false);
		composite.setWireframeColor(org.jzy3d.colors.Color.BLACK);

		Chart chart = new Chart();
		chart.getAxeLayout().setMainColor(Color.BLACK);
		chart.getView().setBackgroundColor(Color.WHITE);
		chart.getScene().add(composite);
		ChartLauncher.openChart(chart);
	}
}
